import datetime
from xml.etree.ElementTree import Element, SubElement, tostring
import xml.etree.ElementTree as ET
from xml.dom import minidom
import threading
import uuid

import requests

from Aes import Aes

class DataService:
    _lock = threading.Lock()
    
    applykey_url = "https://open.mmarket.com/cap/dataservice/ApplyKey.proxy"
    opendata_url = "https://open.mmarket.com/cap/dataservice/appDataServiceAuthen.proxy"
    
    ap_id = "752243"
    app_id = "300012473857"
    app_key = "9EBC9BCB21EBCF7BB01520D50AD8CD0D"
    seq = 0
    key = ""
    
    client_code = "zaixin_sms"
    
    expiry_date = -1
    
    def __init__(self):
        self._data = None

    def get_apply_key(self):
        with DataService._lock:
            date_format = "%Y%m%d%H%M%S"
            now_time = datetime.datetime.now().strftime(date_format)

            if int(now_time) > self.expiry_date:
                url = self.applykey_url + "?clientCode=" + self.client_code
                apply_key_xml = self.do_get(url)

                try:
                    apply_key_map = self.parse_apply_key(apply_key_xml)
                    self.key = apply_key_map.get("key")
                    self.seq = int(apply_key_map.get("seq"))
                    
                    self.expiry_date = (datetime.datetime.strptime(now_time, date_format) + datetime.timedelta(days=1)).strftime(date_format)
                except Exception as e:
                    print(e)
    
    def parse_apply_key(self, xml):
        apply_key_map = {}
        
        try:
            root = ET.fromstring(xml)
            for child in root:
                apply_key_map[child.tag] = child.text
        except Exception as e:
            print(e)
            
        return apply_key_map
        
    def create_xml_phone(self, servCode, modelId, phone, mon):
        OpenDataRequest = Element('OpenDataRequest')
        RequestSEQ = SubElement(OpenDataRequest, 'RequestSEQ')
        RequestTime = SubElement(OpenDataRequest, 'RequestTime')
        APID = SubElement(OpenDataRequest, 'APID')
        APPID = SubElement(OpenDataRequest, 'APPID')
        ServCode = SubElement(OpenDataRequest, 'ServCode')
        ServArgs = SubElement(OpenDataRequest, 'ServArgs')
        
        EncryptPhone = SubElement(ServArgs, 'EncryptPhone')
        ModelId = SubElement(ServArgs, 'ModelId')
        Month = SubElement(ServArgs, 'Month')
        PhoneAuthCode = SubElement(ServArgs, 'PhoneAuthCode')

        # 时间格式为 yyyyMMddHHmmssSSS
        nowTime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        RequestSEQ.text =  self.app_id + nowTime
        RequestTime.text = nowTime
        APID.text = self.ap_id
        APPID.text = self.app_id
        ServCode.text = servCode
        
        EncryptPhone.text = phone
        ModelId.text = modelId
        # 获取当前月份yyyyMM
        Month.text = mon
        # 生成唯一的uuid
        uid = uuid.uuid4()
        PhoneAuthCode.text = str(uid).replace("-", "")

        # utf-8编码
        xml_str = minidom.parseString(tostring(OpenDataRequest)).toprettyxml(indent="   ", encoding="UTF-8")
        xml_str = xml_str.decode("utf-8").replace("\n", "")  

        return xml_str
    
    def create_xml(self, servCode, modelId, uaid, mon):
        open_data_request = Element('OpenDataRequest')
        request_seq = SubElement(open_data_request, 'RequestSEQ')
        request_time = SubElement(open_data_request, 'RequestTime')
        apid = SubElement(open_data_request, 'APID')
        appid = SubElement(open_data_request, 'APPID')
        serv_code = SubElement(open_data_request, 'ServCode')
        serv_args = SubElement(open_data_request, 'ServArgs')
        
        ua_id = SubElement(serv_args, 'UAID')
        # UAIDAppId
        uaid_app_id = SubElement(serv_args, 'UAIDAppId')
        model_id = SubElement(serv_args, 'ModelId')
        month = SubElement(serv_args, 'Month')


        # 时间格式为 yyyyMMddHHmmssSSS
        nowTime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        request_seq.text =  self.app_id + nowTime
        request_time.text = nowTime
        apid.text = self.ap_id
        appid.text = self.app_id
        serv_code.text = servCode
        
        ua_id.text = uaid
        uaid_app_id.text = self.app_id
        model_id.text = modelId
        month.text = mon

        xml_str = minidom.parseString(tostring(open_data_request)).toprettyxml(indent="   ")
        return xml_str
    
    def do_post(self, xml):
        try:
            headers = {
                "Content-Type": "application/xml;charset=utf-8",
                "Authorization": f'accessname="{self.ap_id}#{self.app_id}",clientCode="{self.client_code}",code="{Aes.encrypt(self.ap_id + "#" + self.app_id + "#" + self.app_key + "#" + self.getSeq(), self.key)}",account=""'
            }
            response = requests.post(self.opendata_url, data=xml, headers=headers, timeout=10)
            response.raise_for_status()  # Raise exception if status is not 200
            resp_text = response.text
            return resp_text
        except requests.exceptions.RequestException as e:
            print(e)
            return None
        
    def do_get(self, url):
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()  # Raise exception if status is not 200
            resp_text = response.text
            return resp_text
        except requests.exceptions.RequestException as e:
            print(e)
            return None
        
    # 解析responseXml
    # @param xml string xml字符串
    # @return (responseCode, isBilling, value, isValid)
    def parse_xml(self, xml):
        # <OpenDataResponse> 
        #     <APIDSign>MYqQdGkLU2ONZJGwCJyMqqgokFetEO7uDbPif9jIv0ssqF+XAd59zzHJSB1Doukf8K+kMnYSdzWFS+VunOJrZg==</APIDSign>
        #     <ResponseCode>0</ResponseCode>
        #     <APID>721520</APID>
        #     <ServResult>
        #         <Row>
        #             <AttrList>
        #                 <IsBilling>1</IsBilling>
        #                 <Value>50</Value>
        #                 <IsValid>1</IsValid>
        #             </AttrList>
        #             <Name>manage_value_score</Name>
        #         </Row>
        #     </ServResult>
        #     <APPID>300016379598</APPID>
        #     <ResponseSEQ>2023101314450165400000006001</ResponseSEQ>
        #     <RequestSEQ>202310131446066910001</RequestSEQ>
        #     <ResponseTime>20231013144501654</ResponseTime>
        #     <ServCode>EXTLAB-AA25</ServCode>
        # </OpenDataResponse>
        
        root = ET.fromstring(xml)
        response_code = root.find("ResponseCode").text
        serv_result = root.find("ServResult")
        if response_code == "0" and serv_result is not None:
            is_billing = serv_result.find("Row/AttrList/IsBilling").text
            value = serv_result.find("Row/AttrList/Value").text
            is_valid = serv_result.find("Row/AttrList/IsValid").text
            
            return (response_code, is_billing, value, is_valid)
        else:
            
            return (response_code, None, None, None)
        
    def getSeq(self):
        with DataService._lock:
            self.seq += 1
            return str(self.seq)
    
